package gnss_plugs

import (
	"bytes"
	"dgo/goutils/gnss"
	"dgo/goutils/utils"
	"fmt"
	"os"
	"sort"
	"strings"
	"time"
)

/***
 * 只写一个系统的星历
 */
type GnssRinexEph2xWriter struct {
	Id             string
	Sys            byte
	bodyCnt        int
	curTmpFileName string
	lastFileName   string

	Filefmt   string
	tmpPath   string
	startTime time.Time
	currTime  time.Time
	ionosMap  map[string]*Rinex2XIonosRec
}

func NewGnssRinexEph2xWriter() *GnssRinexEph2xWriter {
	rval := &GnssRinexEph2xWriter{
		Id:       utils.RandKeyString(4),
		Filefmt:  "",
		currTime: time.Time{},
		ionosMap: make(map[string]*Rinex2XIonosRec),
	}
	return rval
}

func (this *GnssRinexEph2xWriter) checkNewFile(curT time.Time) bool {
	str := this.Filefmt
	str = utils.ParseTimeFmt(str, curT)
	//str = strings.Replace(str, "$id$", this.StationId, -1)

	return strings.Compare(this.lastFileName, str) != 0
}

func (this *GnssRinexEph2xWriter) checkFileStart() {
	if len(this.curTmpFileName) == 0 {
		if this.startTime.IsZero() {
			this.startTime = time.Now()
		}
		strFileN := utils.ParseTimeFmt(this.Filefmt, this.startTime)
		this.lastFileName = strFileN
		this.curTmpFileName = TempFilesDirectory + utils.PathSeparator + "~eph." + utils.RandKeyString(5) + ".tmp"
		utils.ForceCreateFilePath(this.curTmpFileName)
		utils.ForceCreateFilePath(this.lastFileName)
	}
}

func (this *GnssRinexEph2xWriter) checkFileEnd() {
	if len(this.curTmpFileName) == 0 {
		return
	}

	// first line
	str := FPrintRinexV(2.11, 2, 9) + FPrintRinexStrV("N:", 13) + " " + gnss.GetNavSysName(this.Sys) + "  NAV DATA"
	str = utils.AddSuffixForWidth(str, 60, " ")
	str += "RINEX VERSION / TYPE\n"

	if this.startTime.IsZero() {
		this.startTime = time.Now()
	}

	str += utils.AddSuffixForWidth(RINEX_TransVer, 20, " ") +
		utils.AddSuffixForWidth(RINEX_CopyRight, 20, " ") +
		utils.AddSuffixForWidth(this.startTime.Format("20060102 150405")+" UTC", 20, " ") +
		"PGM / RUN BY / DATE\n"

	str += this.getIonosHeader()

	str += utils.AddSuffixForWidth("", 60, " ") + "END OF HEADER\n"
	strName := this.lastFileName
	utils.NewFileData(strName, []byte(str))
	//utils.InsertBeforeLineFile()
	utils.AppendAllFile(strName, this.curTmpFileName)
	os.Remove(this.curTmpFileName)
	this.curTmpFileName = ""
	this.ionosMap = make(map[string]*Rinex2XIonosRec)
	this.startTime = utils.ZeroTime
	this.bodyCnt = 0
}

func (this *GnssRinexEph2xWriter) checkGetIonosRec(hcStr string) *Rinex2XIonosRec {
	itm := this.ionosMap[hcStr]
	if itm == nil {
		itm = &Rinex2XIonosRec{}
		itm.timeid = hcStr
		this.ionosMap[hcStr] = itm
	}
	return itm
}

func (this *GnssRinexEph2xWriter) getIonosHeader() string {
	headers := make([]*Rinex2XIonosRec, 0, len(this.ionosMap))
	for _, v := range this.ionosMap {
		headers = append(headers, v)
	}

	sort.Slice(headers, func(i, j int) bool {
		return strings.Compare(headers[i].timeid, headers[j].timeid) < 0
	})

	str := ""
	for _, rec := range headers {
		str += rec.igmas31 + rec.igmas32 + rec.igmas33 + rec.igmas34
	}

	return str
}

func (this *GnssRinexEph2xWriter) OnRecvGnssRecCallBack(sender interface{}, channelid string, subscribeid interface{}, data interface{}, tag interface{}, isBreak *bool) bool {
	if data == nil {
		this.checkFileEnd()
		return true
	}
	rtcmRec, ok := data.(*gnss.GnssRtcmData)
	if ok {
		this.OnRecvGnssDataRec(sender, rtcmRec)
	}
	return true
}

func (this *GnssRinexEph2xWriter) OnRecvGnssDataRec(sender interface{}, rec *gnss.GnssRtcmData) {
	if rec.Sys != this.Sys {
		return
	}

	if rec.TypeId == gnss.TYPE_EPH {
		if eph, ok := rec.Data.(*gnss.RtcmEph); ok {

			if this.checkNewFile(rec.RtcmTime) {
				this.checkFileEnd() // 上个文件处理

				this.startTime = rec.RtcmTime

				if this.startTime.IsZero() {
					this.startTime = time.Now()
				}

				// 初始化新文件
				this.checkFileStart()
			}

			str := eph.GetRinexStr()
			_, err := utils.AppendFile(this.curTmpFileName, []byte(str))
			if err != nil {
				utils.Log.Errf("写入出现异常:%s, 文件:%s", err.Error(), this.curTmpFileName)
			}
			this.bodyCnt++
		}
	}

	hcStr := utils.ToHourChr(time.Now().UTC())
	if !rec.RefUtc.IsZero() {
		hcStr = utils.ToHourChr(rec.RefUtc)
	}

	if rec.MsgId == 31 {
		if rec31, ok := rec.Data.(*gnss.Gnss31Bds); ok {
			itm := this.checkGetIonosRec(hcStr)
			str := fmt.Sprintf("BDSA %s%s%s%s %s     IONOSPHERIC CORR\n", FPrintRinexEV(rec31.BDS_Alpha0, 4), FPrintRinexEV(rec31.BDS_Alpha1, 4),
				FPrintRinexEV(rec31.BDS_Alpha2, 4), FPrintRinexEV(rec31.BDS_Alpha3, 4), hcStr)
			str += fmt.Sprintf("BDSB %s%s%s%s %s     IONOSPHERIC CORR\n", FPrintRinexEV(rec31.BDS_Beta0, 4), FPrintRinexEV(rec31.BDS_Beta1, 4),
				FPrintRinexEV(rec31.BDS_Beta2, 4), FPrintRinexEV(rec31.BDS_Beta3, 4), hcStr)
			itm.igmas31 = str
		}
	} else if rec.MsgId == 32 {
		if bds32Rec, ok := rec.Data.(*gnss.Gnss32Bds); ok {
			rec32 := bds32Rec

			str := fmt.Sprintf("BDS1 %s%s%s%s %s     IONOSPHERIC CORR\n", FPrintRinexEV(rec32.BDS_Alpha1, 4), FPrintRinexEV(rec32.BDS_Alpha2, 4),
				FPrintRinexEV(rec32.BDS_Alpha3, 4), string(bytes.Repeat([]byte(" "), 12)), hcStr)
			str += fmt.Sprintf("BDS2 %s%s%s%s %s     IONOSPHERIC CORR\n", FPrintRinexEV(rec32.BDS_Alpha4, 4), FPrintRinexEV(rec32.BDS_Alpha5, 4),
				FPrintRinexEV(rec32.BDS_Alpha6, 4), string(bytes.Repeat([]byte(" "), 12)), hcStr)
			str += fmt.Sprintf("BDS3 %s%s%s%s %s     IONOSPHERIC CORR\n", FPrintRinexEV(rec32.BDS_Alpha7, 4), FPrintRinexEV(rec32.BDS_Alpha8, 4),
				FPrintRinexEV(rec32.BDS_Alpha9, 4), string(bytes.Repeat([]byte(" "), 12)), hcStr)

			itm := this.checkGetIonosRec(hcStr)
			itm.igmas32 = str
		}
	} else if rec.MsgId == 33 {
		if rec33, ok := rec.Data.(*gnss.IgmasIonos); ok {

			str := fmt.Sprintf("GPSA %s%s%s%s %s     IONOSPHERIC CORR\n", FPrintRinexEV(rec33.Alpha0, 4), FPrintRinexEV(rec33.Alpha1, 4),
				FPrintRinexEV(rec33.Alpha2, 4), FPrintRinexEV(rec33.Alpha3, 4), hcStr)
			str += fmt.Sprintf("GPSB %s%s%s%s %s     IONOSPHERIC CORR\n", FPrintRinexEV(rec33.Beta0, 4), FPrintRinexEV(rec33.Beta1, 4),
				FPrintRinexEV(rec33.Beta2, 4), FPrintRinexEV(rec33.Beta3, 4), hcStr)

			itm := this.checkGetIonosRec(hcStr)
			itm.igmas33 = str
		}
	} else if rec.MsgId == 34 {
		if rec34, ok := rec.Data.(*gnss.IgmasGalileoIonos); ok {
			str := fmt.Sprintf("GAL  %s%s%s%s %s     IONOSPHERIC CORR\n",
				FPrintRinexEV(rec34.Ai0, 4), FPrintRinexEV(rec34.Ai1, 4),
				FPrintRinexEV(rec34.Ai2, 4), string(bytes.Repeat([]byte(" "), 12)), hcStr)

			itm := this.checkGetIonosRec(hcStr)
			itm.igmas34 = str
		}
	}
}
